//
//  HisunStr.m
//  IPos
//
//  Created by hisuntech on 11-8-11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "EncryptStr.h"
#import "Base64.h"
#import "GTMBase64.h"


@implementation EncryptStr

@synthesize byteArryLen;
@synthesize intArrayLen;

static EncryptStr *SharedInstance = nil;

+(EncryptStr*)getInstance
{
    @synchronized(self)
    {
        if (SharedInstance == nil)
        {
            SharedInstance = [[self alloc] init];
        }
    }
    return SharedInstance;
}

-(void)dealloc{
//    free(encryptDataInt);
//    free(encryptKeyInt);
//    free(decryptDataInt);
//    free(decryptKeyInt);
    
    SharedInstance=nil;
}


-(NSString*) base64Encode:(Byte[]) data  dataLen:(int)dataLen
{
    int len = dataLen;
    NSData * ecncodeData = [GTMBase64 encodeBytes:data length:len];
    NSString* retString = [[NSString alloc]initWithData:ecncodeData encoding:NSUTF8StringEncoding];
    
    NSLog(@"retString=%@",retString);

    return retString;
}

-(NSData*)base64EncodeToData:(Byte[]) data  dataLen:(int)dataLen
{
    int len = dataLen;
    NSData * ecncodeData1 = [GTMBase64 encodeBytes:data length:len];
    NSData * ecncodeData = [[NSData alloc]initWithData:ecncodeData1];
    return ecncodeData;
}

-(Byte*) base64Decode:(NSString*) data
{
    //    NSData* decodeData = [GTMBase64 decodeString:data];
    //    Byte* decodeBytes = (Byte*)[decodeData bytes];
    //    return decodeBytes;
    
    NSData* decodeData = [GTMBase64 decodeBytes:[data UTF8String] length:data.length];
    Byte* decodeBytes = (Byte*)[decodeData bytes];
    return decodeBytes;
}

-(Byte*) base64Decode:(NSString*) data len:(int*)len
{
//		return Base64.decode(data, Base64.NO_WRAP);
    
//    NSData* decodeData = [GTMBase64 decodeString:data];
//    Byte* decodeBytes = (Byte*)[decodeData bytes];
//    return decodeBytes;
    
    NSData* decodeData = [GTMBase64 decodeBytes:[data UTF8String] length:data.length];
    *len = decodeData.length;
    Byte* decodeBytes = (Byte*)[decodeData bytes];
    return decodeBytes;
}

-(Byte*) base64DecodeByte:(Byte[]) data dataLen:(int)dataLen
{
//    return base64Decode(new String(data));
    
    NSData* decodeData = [GTMBase64 decodeBytes:data length:dataLen];
    Byte* decodeBytes = (Byte*)[decodeData bytes];
    return decodeBytes;
}



-(NSString*) encryptWithBase64:(Byte[]) data dataLen:(int)dataLen  key:(Byte[]) key keyLen:(int)keyLen
{
    //    return base64Encode(encrypt(data, key));
    int restByteLen;
    Byte* encryptByte = [self encrypt:data dataLen:dataLen key:key keyLen:keyLen returnBetyLen:&restByteLen];
    return [self base64Encode:encryptByte dataLen:dataLen];
}

-(NSString*) encryptWithBase64:(NSString*) data dataLen:(int)dataLen key:(Byte[]) key keyLen:(int)keyLen encoding:(NSStringEncoding) encoding
{
    //    return base64Encode(encrypt(data.getBytes(encoding), key));
    int restByteLen;
    Byte* encryptByte = [self encrypt:(Byte*)[data cStringUsingEncoding:encoding] dataLen:dataLen key:key keyLen:keyLen returnBetyLen:&restByteLen];
    return [self base64Encode:encryptByte dataLen:dataLen];
}


//int* encryptDataInt;
//int* encryptKeyInt;

/**
 * Encrypt data with key.
 *
 * @param data
 * @param key
 * @return
 */
int dataIntLen;
-(Byte*) encrypt:(Byte[]) data dataLen:(int)dataLen  key:(Byte[]) key keyLen:(int)keyLen returnBetyLen:(int*)returnBetyLen
{
    if (dataLen == 0) {
        return data;
    }

//    int dataIntLen;
    int*encryptDataInt = [self toIntArray:data datalen:dataLen is:YES returnBetyLen:&dataIntLen];

    int keyIntLen;
    int*encryptKeyInt = [self toIntArray:key datalen:keyLen is:NO returnBetyLen:&keyIntLen];

    int* encryptInt = [self encrypt:encryptDataInt vLen:dataIntLen k:encryptKeyInt kLen:keyLen];

    Byte* encryptRestByte = [self toByteArray:encryptInt datalen:dataIntLen includeLength:NO returnBetyLen:returnBetyLen];
//    base64Byte[0]=7 base64Byte[3]=89 base64Byte[30]=2
//
//    free(encryptInt);
//    free(encryptKeyInt);
//    free(encryptDataInt);
//    realloc(encryptDataInt, dataIntLen);
    
    
    return encryptRestByte;
}

//int* decryptDataInt;
//int* decryptKeyInt;
/**
 * Decrypt data with key.
 *
 * @param data
 * @param key
 * @return
 */
-(Byte*) decrypt:(Byte[]) data dataLen:(int)dataLen  key:(Byte[]) key keyLen:(int)keyLen returnBetyLen:(int*)returnBetyLen
{
    if (dataLen == 0) {
        return nil;
    }
    
    int dataIntLen1;
    int*decryptDataInt = [self toIntArray:data datalen:dataLen is:NO returnBetyLen:&dataIntLen1];

    int keyIntLen;
    int*decryptKeyInt = [self toIntArray:key datalen:keyLen is:NO returnBetyLen:&keyIntLen];

    int* decryptInt = [self decrypt:decryptDataInt vLen:dataIntLen1 k:decryptKeyInt kLen:keyLen ];//这里的长度一定是16？

    Byte* restByte = [self toByteArray:decryptInt datalen:dataIntLen1 includeLength:YES returnBetyLen:returnBetyLen];//这里的长度一定是16？
    
//    free(decryptInt);
//    free(decryptKeyInt);
    
    return restByte;
    
    
}

/**
 * @param data
 * @param key
 * @param encoding
 * @return
 * @throws IOException
 * @throws HiException
 */
-(Byte*) decryptWithBase64:(NSString*) data dataLen:(int)dataLen key:(Byte[]) key keyLen:(int)keyLen encoding:(NSStringEncoding) encoding returnBetyLen:(int*)returnBetyLen
{
    if (NULL == data || dataLen == 0) {
        return nil;
    }
//    return decrypt(base64Decode(data), key);
    
    Byte* base64Byte=[self base64Decode:data];
    Byte* restByte = [self decrypt:base64Byte dataLen:dataLen key:key keyLen:keyLen returnBetyLen:returnBetyLen];
    return restByte;
}

/**
 * @param data
 * @param key
 * @param encoding
 * @return
 * @throws IOException
 */
-(Byte*) decryptWithBase64:(Byte[]) data dataLen:(int)dataLen key:(Byte[]) key keyLen:(int)keyLen returnBetyLen:(int*)returnBetyLen
{
    if (dataLen == 0) {
        return nil;
    }
//    return decrypt(base64Decode(data), key);
    
    Byte* base64Byte=[self base64DecodeByte:data dataLen:dataLen];
    Byte* restByte = [self decrypt:base64Byte dataLen:dataLen key:key keyLen:keyLen returnBetyLen:returnBetyLen];
    return restByte;
}

/**
 * Encrypt data with key.
 *
 * @param v
 * @param k
 * @return
 */
-(int*) encrypt:(int[])v  vLen:(int)vLen  k:(int[])k kLen:(int)kLen
{
    int n = vLen - 1;
    
    if (n < 1) {
        return v;
    }
    if (kLen < 4)
    {
        int key[4];
        for (int i=0; i<kLen; i++) {
            key[i]=k[i];
        }
        
        for (int i=0; i<4; i++) {
            k[i]=key[i];
        }
       
    }
    int z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e;
    int p, q = 6 + 52 / (n + 1);
    
    while (q-- > 0) {
        sum = sum + delta;

         e = (((unsigned int)sum) >> 2) & 3;
        
        for (p = 0; p < n; p++) {
            y = v[p + 1];
            z = v[p] += (((unsigned int)z) >> 5 ^ y << 2) + (((unsigned int)y) >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        }
        
        y = v[0];
        z = v[n] += (((unsigned int)z) >> 5 ^ y << 2) + (((unsigned int)y) >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
    }

    return v;
}


/**
 * Decrypt data with key.
 *
 * @param v
 * @param k
 * @return
 */
-(int*) decrypt:(int[])v  vLen:(int)vLen  k:(int[])k kLen:(int)kLen
{
//    int n = v.length - 1;
    int n = vLen-1;
    
    if (n < 1) {
        return v;
    }
    if (kLen < 4) {
        int key[4];
        for (int i=0; i<kLen; i++) {
            key[i]=k[i];
        }
        
        for (int i=0; i<4; i++) {
            k[i]=key[i];
        }
    }
    int z = v[n], y = v[0], delta = 0x9E3779B9, sum, e;
    int p, q = 6 + 52 / (n + 1);
    
    sum = q * delta;
    while (sum != 0) {

        e = ((unsigned int)sum) >> 2 & 3;
        
        for (p = n; p > 0; p--) {
            z = v[p - 1];

            y = v[p] -= (((unsigned int)z) >> 5 ^ y << 2) + (((unsigned int)y) >> 3 ^ z << 4) ^ (sum ^ y)+ (k[p & 3 ^ e] ^ z);
            
        }
        z = v[n];
  
        y = v[0] -= (((unsigned int)z) >> 5 ^ y << 2) + (((unsigned int)y) >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        
        sum = sum - delta;
        
    }
    
    
    return v;
}

/**
 * Convert byte array to int array.
 *
 * @param data
 * @param includeLength
 * @return
 */
-(int*) toIntArray:(Byte[]) data datalen:(int)datalen is:(BOOL)includeLength returnBetyLen:(int*)returnBetyLen
{
    int dataLen = datalen;
    
    int n = (((dataLen & 3) == 0) ? (((unsigned int)dataLen) >> 2) : ((((unsigned int)dataLen) >> 2) + 1));
    
    int *result=nil;
    if (includeLength) {
//        result =(int*)malloc(n+1);
        result = new int[n+1];
        intArrayLen = n+1;
    }
    else {
//        result =(int*)malloc(n);
        result = new int[n];
        
        intArrayLen = n;
    }
    
    //初始化数组result
    for (int i = 0; i < n; i++) {
        result[i]=0;
    }
    
    n=dataLen;
    for (int i = 0; i < n; i++) {
        int idx = ((unsigned int)i) >> 2;
        result[idx] |= (0x000000ff & data[i]) << ((i & 3) << 3);
        
    }
    
    if (includeLength) {
        //        intArrayLen = n+1;
        result[intArrayLen-1]=datalen;
    }
    else {
        //        intArrayLen = n;
    }

    *returnBetyLen = intArrayLen;
    
    return result;
}


///**
// * Convert byte array to int array.
// *
// * @param data
// * @param includeLength
// * @return
// */
//-(int*) toIntArray:(Byte[]) data datalen:(int)datalen is:(BOOL)includeLength returnBetyLen:(int*)returnBetyLen
//{
//    int dataLen = datalen;
//
//    int n = (((dataLen & 3) == 0) ? (((unsigned int)dataLen) >> 2) : ((((unsigned int)dataLen) >> 2) + 1));
//    
//    int*result=0;
//    if (includeLength) {
//
//        result =(int*)malloc(n+1);
//        result[n]=dataLen;
//        
//        intArrayLen = n+1;
//    }
//    else {
//        result =(int*)malloc(n);
//        
//        intArrayLen = n;
//    }
//    
//    n=dataLen;
//    for (int i = 0; i < n; i++) {
//        int idx = ((unsigned int)i) >> 2;
//        
//        result[i]=0;
//        
//        result[idx] |= (0x000000ff & data[i]) << ((i & 3) << 3);
//
//    }
//    
//    if (includeLength) {
////        intArrayLen = n+1;
//        result[intArrayLen-1]=datalen;
//    }
//    else {
////        intArrayLen = n;
//    }
//
//    *returnBetyLen = intArrayLen;
//    
//    return result;
//}


/**
 * Convert int array to byte array.
 *
 * @param data
 * @param includeLength
 * @return
 */
-(Byte*) toByteArray:(int[]) data datalen:(int)datalen includeLength:(BOOL) includeLength returnBetyLen:(int*)returnBetyLen
{
    int dataLen = datalen;
    int n=dataLen<<2;
    
    if (includeLength) {
        int m=data[dataLen-1];
        NSLog(@"m=%d",m);
        
        if (m > n | m<0) {
            return nil;
        }
        else {
            n = m;
        }
    }
//    Byte* result2 =(Byte*)malloc(n);
    Byte* result2 = new Byte[n];
    //初始化数组result2
    for (int i = 0; i < n; i++) {
        result2[i]=0;
    }
    
    for (int i = 0; i < n; i++) {
        result2[i] = (Byte) (( ((unsigned int) data[((unsigned int)i) >> 2]) >> ((i & 3) << 3)) & 0xff);
        
    }
    
    byteArryLen = n;
    *returnBetyLen = n;
    
    return result2;
}

-(NSData*)startEncryptData:(NSData*)srcData key:(NSString*)key{
    
    Byte* encodingDataByte;
//    [srcData getBytes:encodingDataByte];
    [srcData getBytes:encodingDataByte length:srcData.length];
    
    //        int tmplen = [srcData dataUsingEncoding:NSUTF8StringEncoding].length;
    int srcDataLen = srcData.length;
    int keyLen = [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    Byte*encodingKeyByte = (Byte*)[key cStringUsingEncoding:NSUTF8StringEncoding];
    int restEncryptByteLen;
    Byte* encryptByte =[self encrypt:encodingDataByte dataLen:srcDataLen key:encodingKeyByte keyLen:keyLen returnBetyLen:&restEncryptByteLen];
    NSLog(@"encryptByte[0]=%d encryptByte[3]=%d",encryptByte[0],encryptByte[3]);
//    NSString* encData = [self base64Encode:encryptByte dataLen:restEncryptByteLen];
    NSData* encData = [self base64EncodeToData:encryptByte dataLen:restEncryptByteLen];
    NSLog(@"encData:%@,len:%d",encData,encData.length);
    
//    free(encryptByte);
    return encData;
    
}

-(NSString*)startEncrypt:(NSString*)srcData key:(NSString*)key
{
    Byte* encodingDataByte = (Byte*)[srcData UTF8String];
    int srcDataLen = [srcData lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    int keyLen = [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    Byte*encodingKeyByte = (Byte*)[key cStringUsingEncoding:NSUTF8StringEncoding];
    int restEncryptByteLen;
    Byte* encryptByte =[self encrypt:encodingDataByte dataLen:srcDataLen key:encodingKeyByte keyLen:keyLen returnBetyLen:&restEncryptByteLen];
    NSString* encData = [self base64Encode:encryptByte dataLen:restEncryptByteLen];
    //        NSString* encData = [self base64Encode:encryptByte dataLen:byteArryLen];
    NSLog(@"encData:%@,len:%d",encData,encData.length);
    
//    free(encryptByte);
    return encData;

}


-(NSString*)startDeencrypt:(NSString*)encData key:(NSString*)key
{
//    encData = @"Byn8Wdtg2R8aNU2wwuKHID7gZxDfqoY1dXTerWR1AoLS3hiRIccdXYZwA46dy/Ouvqdj8GqUOr9YlM5ADj5Weg==";
//    encData = @"nNsJdi43kFOhI/UJb3XDTuYeI8fqvlWXUxcwrRmDgmVSZhgelezYvadxK11baDPZt1/5Oa/1akOxlgDK92JoUVdfGHVgzd/o5hjKRDZtZxcWNWokBsb+6rUIFJcR02sOFwPdpMu5lzlsBIYPoVOwVvs6oqWJI60K6W3V0AGZZQDunVkJpyWxu27R68m/nDPtljsJohh2CgJSdhXvlXGVYpqiRjJBSNnFUJX7Pw/fx965x++n87Kg4ptd1tCtBgLoQv9jn6TB3w43LexXirGH7QAL4+1yTXKbhQtxUYpshBmeHHX4r2Rzqk/WccO84JZC2Ma0MrBbEYhIon7r9Z48AbRmhbFWJZams8gjRD02/NjKnWTyD4SiXMAI3jbyUkvnrhfWG+2ShV1COG8spNAb2FoT/iTe+mLMNG+jU3giZZkFsDCLBvkHxqvRaOGxBzVzgcUvbgRgO3xl/nXffr5IqQDoH2IqAZQQIHdDqQ0AJxADOGZCfLnWpGoAOKDkTFY998txnMufmHrGmp6/SH+Kt0jRIKt3WW+Lz6FKPweztg6Va+bC2c+TBcp3u6b3LHfSLf95DKEmqRgfp/ko2spmAE3fhpAuxl1pimN56yN3d2r6je9ZSGLjZNREHGNv974yc6NMbE0jtzZYi/KpvA2Sc8qr0Q3qJ56Dt0XYNW+/LwM=";
    
    int encDataLen;
    Byte* base64Byte = [self base64Decode:encData len:&encDataLen];
    
    int restDecodeByteLen;
    Byte* decodeByte = [self decrypt:base64Byte dataLen:encDataLen key:(Byte*)[key UTF8String] keyLen:key.length returnBetyLen:&restDecodeByteLen];
    
    NSString* decodeStr=@"";
    if (decodeByte==nil) {
        decodeStr=@"";
    }else{
        decodeStr = [[NSString alloc]initWithBytes:decodeByte length:restDecodeByteLen encoding:NSUTF8StringEncoding];
    }
    NSLog(@"decData:%@,decodeStr.length:%d,decodeStr.lengthOfBytesUsingEncoding:%d",decodeStr,decodeStr.length,[decodeStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
    
//    free(decodeByte);
    return decodeStr;
}



/****************
-(void) test {
    NSString* key = @"1234567890123456";
    NSString* srcData = @"123ABC中文字符2014-9-11 17:22:402014年9月11日17:22:45";
    
    
    @try {
        Byte* encodingDataByte = (Byte*)[srcData UTF8String];
//        int tmplen = [srcData dataUsingEncoding:NSUTF8StringEncoding].length;
        int srcDataLen = [srcData lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        int keyLen = [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        Byte*encodingKeyByte = (Byte*)[key cStringUsingEncoding:NSUTF8StringEncoding];
        int restEncryptByteLen;
        Byte* encryptByte =[self encrypt:encodingDataByte dataLen:srcDataLen key:encodingKeyByte keyLen:keyLen returnBetyLen:&restEncryptByteLen];
        NSLog(@"encryptByte[0]=%d encryptByte[3]=%d",encryptByte[0],encryptByte[3]);
        NSString* encData = [self base64Encode:encryptByte dataLen:restEncryptByteLen];
//        NSString* encData = [self base64Encode:encryptByte dataLen:byteArryLen];
        NSLog(@"encData:%@,len:%d",encData,encData.length);
        
        
//        测试数据
//        Byn8Wdtg2R8aNU2wwuKHID7gZxDfqoY1dXTerWR1AoLS3hiRIccdXYZwA46dy/Ouvqdj8GqUOr9YlM5ADj5Weg==
        
    
//        NSString* encData = @"Byn8Wdtg2R8aNU2wwuKHID7gZxDfqoY1dXTerWR1AoLS3hiRIccdXYZwA46dy/Ouvqdj8GqUOr9YlM5ADj5Weg==";
        Byte* base64Byte = [self base64Decode:encData];
        int encDataLen = [encData lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"base64Byte[0]=%d base64Byte[3]=%d base64Byte[30]=%d",base64Byte[0],base64Byte[3],base64Byte[30]);
        //base64Byte[0]=7 base64Byte[3]=89 base64Byte[30]=2
        int restDecodeByteLen;
        Byte* decodeByte = [self decrypt:base64Byte dataLen:encDataLen key:(Byte*)[key UTF8String] keyLen:key.length returnBetyLen:&restDecodeByteLen];
        NSLog(@"decodeByte[0]=%d decodeByte[3]=%d",decodeByte[0],decodeByte[3]);
//        NSString* decodeStr = [[NSString alloc]initWithBytes:decodeByte length:byteArryLen encoding:NSUTF8StringEncoding];
        NSString* decodeStr = [[NSString alloc]initWithBytes:decodeByte length:restDecodeByteLen encoding:NSUTF8StringEncoding];
        
        NSLog(@"decData:%@,len:%d",decodeStr,decodeStr.length);
        
//        free(encryptByte);
//        free(decodeByte);
    }
    @catch (NSException *exception) {
        
    }
    @finally {
        
    }
}
************/



@end
